package com.wontube.smr.web.pub;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.wontube.client.extension.remote.cache.ICacheHandler;
import com.wontube.client.remote.Remoting;

/**
 * @author tanggf(2012-5-15)
 *
 */
public class PageCacheFilter implements Filter{
	private final static Logger logger = LoggerFactory.getLogger(PageCacheFilter.class);
	
	private ExecutorService executorService;
	private final static String PAGE_CACHE_NAME = "smr_page_cache_";
	private final static int time2live = 60 * 60;
	private final static int time2idle = 60 * 60;
	
	private static String[] useCachePaths = null;
	private static boolean useCache = false;
	
	@Override
	public void destroy() {				
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp,
			FilterChain chain) throws IOException, ServletException {
			HttpServletRequest request = (HttpServletRequest)req;
			HttpServletResponse response = (HttpServletResponse)resp;
			if(useCache(request) && useCache){
				String html = getFromCache(request);
				if(html != null){
					response.getWriter().write(html);
				}else{
					PageCacheResponseWrapper wrapper = new PageCacheResponseWrapper(response);
					chain.doFilter(request, wrapper);
					
					//cache
					html = new String(wrapper.getDataAsBytes());					
					response.getWriter().write(html);
					putToCache(request, html);
				}				
			}else{
				chain.doFilter(request, response);
			}			
	}

	private void putToCache(HttpServletRequest request, String html) {
		String key = getKey(request);
		CachePutRunner runner = new CachePutRunner(key, html);
		this.executorService.execute(runner);
	}

	private String getFromCache(HttpServletRequest request) {
		String key = getKey(request);
		Remoting<ICacheHandler> remoting = new Remoting<ICacheHandler>();
		remoting.setDataFormat(Remoting.dataFormatHessian);
		ICacheHandler handler = remoting.createService(ICacheHandler.class);
		String html = handler.getUserCache(PAGE_CACHE_NAME, key);
		if(remoting.isDone() && html != null){
			logger.info("get page <{}> from cache", key);
			return html;
		}
		return null;
	}

	private String getKey(HttpServletRequest request) {
		return request.getServletPath();
	}

	private boolean useCache(HttpServletRequest request) {
		if(useCachePaths == null || useCachePaths.length == 0){
			return false;
		}
		String path = request.getServletPath();
		for (String use : useCachePaths) {			
			if(path.matches(use)){
				return true;
			}
		}
		return false;
	}

	@Override
	public void init(FilterConfig config) throws ServletException {			
		String paths = config.getInitParameter("useCachePaths");
		if(paths != null){
			paths = paths.trim();
			if(paths.length() > 0){
				useCachePaths = paths.split("\\s*,\\s*");
			}
		}
		
		String cached = config.getInitParameter("useCache");
		if(("true").equalsIgnoreCase(cached)){
			useCache = true;
		}
		
		if(useCachePaths != null && useCache){
			this.executorService = Executors.newCachedThreadPool();
		}
	}
	
	private class CachePutRunner implements Runnable {		
		private String key;
		private String html;
		public CachePutRunner(String key, String html) {
			this.key = key;
			this.html = html;
		}
		
		@Override
		public void run() {
			Remoting<ICacheHandler> remoting = new Remoting<ICacheHandler>();
			remoting.setDataFormat(Remoting.dataFormatHessian);
			ICacheHandler handler = remoting.createService(ICacheHandler.class);
			handler.putUserCache(PAGE_CACHE_NAME, key, time2live, time2idle, html);
			logger.info("put page <{}> to cache", key);			
		}
	}
}
